/*
 * Pantomime.java
 *
 * Created on Nov 7, 2011, 11:15:54 PM
 */
package GUI;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.util.Random;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import pantomime.gestures.GestureMain;
import processing.core.PApplet;


public class Pantomime extends PApplet{
	
	public class pnlBeginCalibration extends javax.swing.JPanel
	implements Runnable{

    /** Creates new form pnlBeginCalibration */
    public pnlBeginCalibration() {
    	this.setPreferredSize(new Dimension(500, 200));
        initComponents();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
    	
        pbCalibrationProgress = new javax.swing.JProgressBar(0, 9000);
     
        jLabel1 = new javax.swing.JLabel();
        jButton1 = new javax.swing.JButton();
        jButton2 = new javax.swing.JButton();
        lblCalibrationProgress = new javax.swing.JLabel();

        lblCalibrationProgress.setFont(new Font("Serif", Font.PLAIN, 24));
        jButton1.setText("Cancel");        
        jButton2.setText("       Begin       ");
        
        jButton2.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jButton2MouseReleased(evt);
            }
        });

        lblCalibrationProgress.setText("Hold your hand flat to begin calibration.        ");

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(

            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(76, 76, 76)
                .add(jLabel1)
                .addContainerGap(276, Short.MAX_VALUE))
            .add(layout.createSequentialGroup()
                .add(33, 33, 33)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                    .add(lblCalibrationProgress, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(layout.createSequentialGroup()
                        .add(jButton2)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(jButton1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 86, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(pbCalibrationProgress, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE))
                .addContainerGap(43, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(31, 31, 31)
                .add(jLabel1)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(lblCalibrationProgress)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(pbCalibrationProgress, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jButton2)
                    .add(jButton1))
                .addContainerGap(36, Short.MAX_VALUE))
        );
        this.setSize(300,200);
    }//end initComponents
    
    private void jButton2MouseReleased(java.awt.event.MouseEvent evt) {
    	
        model.restartSerial();
    	pnlModel = new pnlModel(model);
    	tabbedPane.remove(2);
        tabbedPane.addTab("3D Model", pnlModel);
        
    	Thread animation = new Thread(this);
    	animation.start();   	
    }

    	public void run(){
    		lblCalibrationProgress.setText("Hold your hand flat to begin calibration.          ");
    		
    		long msElapsed = 0;
        	long msCalBegin = System.currentTimeMillis();
        	boolean bSet = false;
        	while(msElapsed < 9000){
        		if(msElapsed > 4500 && ! bSet){
        			lblCalibrationProgress.setText("Hold your hand in a fist to continue calibration.");
        		}
            	msElapsed =  (System.currentTimeMillis() - msCalBegin);
            	pbCalibrationProgress.setValue((int)msElapsed);   		
        	}
        	
        	lblCalibrationProgress.setText("Calibration Complete!                                          ");
    	}
    	
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel lblCalibrationProgress;
    private javax.swing.JProgressBar pbCalibrationProgress;
}//end class pnlBeginCalibration


	public class pnlRPS extends javax.swing.JPanel{

	    /** Creates new form pnlRPS */
	    public pnlRPS() {
	        initComponents();
	    }

	    @SuppressWarnings("unchecked")
	    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
	    private void initComponents() {
	    	
	    	win = 0;
	    	loss = 0;

	        jSeparator1 = new javax.swing.JSeparator();
	        jLabel1 = new javax.swing.JLabel();
	        jLabel2 = new javax.swing.JLabel();
	        jLabel3 = new javax.swing.JLabel();
	        jButton1 = new javax.swing.JButton(); 
	        jButton2 = new javax.swing.JButton();
	        jTextField1 = new javax.swing.JTextField();
	        jLabel4 = new javax.swing.JLabel();
	        jTextField2 = new javax.swing.JTextField();
	        jSeparator2 = new javax.swing.JSeparator();
	        jSeparator3 = new javax.swing.JSeparator();
	        jLabel5 = new javax.swing.JLabel();
	        jLabel6 = new javax.swing.JLabel();
	        
	        setPreferredSize(new Dimension(500, 500));

	        setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
	        add(jSeparator1, new org.netbeans.lib.awtextra.AbsoluteConstraints(32, 101, -1, -1));

	        jLabel1.setText("Player Input:");
	        add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 20, -1, -1));

	        jLabel2.setText("Computer:");
	        add(jLabel2, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 131, -1, -1));
	        add(jLabel3, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 91, -1, -1));

	        jButton1.setText("Recognize Input");
	        jButton1.addMouseListener(new java.awt.event.MouseAdapter() {
	            public void mouseReleased(java.awt.event.MouseEvent evt) {
	                jButton1MouseReleased(evt);
	            }
	        });
	        add(jButton1, new org.netbeans.lib.awtextra.AbsoluteConstraints(32, 45, -1, -1));

	        //jTextField1.setText("Rock");
	        add(jTextField1, new org.netbeans.lib.awtextra.AbsoluteConstraints(184, 45, 111, -1));

	        jLabel4.setText("Randomly Generated:");
	        add(jLabel4, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 167, -1, -1));

	        //jTextField2.setText("Scissors");
	        add(jTextField2, new org.netbeans.lib.awtextra.AbsoluteConstraints(187, 161, 109, -1));
	        add(jSeparator2, new org.netbeans.lib.awtextra.AbsoluteConstraints(44, 101, 251, -1));
	        add(jSeparator3, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 203, 256, 10));

	        //jLabel5.setText("You Win!");
	        add(jLabel5, new org.netbeans.lib.awtextra.AbsoluteConstraints(40, 225, -1, -1));
	        
	        jButton2.setText("Reset Scores");
	        jButton2.addMouseListener(new java.awt.event.MouseAdapter() {
	            public void mouseReleased(java.awt.event.MouseEvent evt) {
	                jButton2MouseReleased(evt);
	            }
	        });
	        add(jButton2, new org.netbeans.lib.awtextra.AbsoluteConstraints(32, 275, -1, -1));
	        
	        jLabel6.setText("Wins: " + win + "   Losses: " + loss);
	        add(jLabel6, new org.netbeans.lib.awtextra.AbsoluteConstraints(184, 280, -1, -1));
	    }//end initComponents                       

	    
	    private void jButton1MouseReleased(java.awt.event.MouseEvent evt) {                                       
	    	
	    	String computer;
	        
	    	//Get the gesture name
	    	String gestureName = model.recognize();
	    	
	    	//Adding in more acceptable gestures for rock, paper, and scissor
	    	if(gestureName.equalsIgnoreCase("numbertwo") || gestureName.equalsIgnoreCase("twoFingerPoint"))
	    		gestureName = "Scissors";
	    	else if(gestureName.equalsIgnoreCase("numberFive") || gestureName.equalsIgnoreCase("handShake") ||
	    			gestureName.equalsIgnoreCase("fourFingerPoint") || gestureName.equalsIgnoreCase("edwardScissorHand") ||
	    			gestureName.equalsIgnoreCase("numberFour"))
	    		gestureName = "Paper";
	    	else if(gestureName.equalsIgnoreCase("poundIt") || gestureName.equalsIgnoreCase("thumbsDown") || 
	    			gestureName.equalsIgnoreCase("thumbsUp") || gestureName.equalsIgnoreCase("cheer"))
	    		gestureName = "Rock";
	    	
	    	
	    	//It must be a valid gesture for the game if not we tell them its invalid and ask them to try again
	    	if(gestureName.equalsIgnoreCase("Rock") || gestureName.equalsIgnoreCase("Paper") || gestureName.equalsIgnoreCase("Scissors")){
	    	
		    	Random rand = new Random();
		    	int temp = rand.nextInt(3);
		    		
		    	if(temp == 0)
		    		computer = "Rock";
		    	else if(temp == 1)
		    		computer = "Paper";
		    	else if(temp == 2)
		    		computer = "Scissors";
		    	else
		    		computer = "Problem with random";	//I tested and this will never happen but better to have something than nothing
		    	
		    	jTextField1.setText(gestureName);
		    	jTextField2.setText(computer);
		    	
		    	if(computer.equalsIgnoreCase(gestureName)){
		    			jLabel5.setText("Tie");
		    	}
		    	else if(gestureName.equalsIgnoreCase("Rock")){
		    		if(computer.equalsIgnoreCase("Paper")){
		    			jLabel5.setText("You Lose");
		    			loss++;
		    		}
		    		else if(computer.equalsIgnoreCase("Scissors")){
		    			jLabel5.setText("You Win!");
		    			win++;
		    		}
		    	}
		    	else if(gestureName.equalsIgnoreCase("Paper")){
		    		if(computer.equalsIgnoreCase("Rock")){
		    			jLabel5.setText("You Win!");
		    			win++;
		    		}
		    		else if(computer.equalsIgnoreCase("Scissors")){
		    			jLabel5.setText("You Lose");
		    			loss++;
		    		}
		    	}
		    	else{
		    		if(computer.equalsIgnoreCase("Paper")){
		    			jLabel5.setText("You Win!");
		    			win++;
		    		}
		    		else if(computer.equalsIgnoreCase("Rock")){
		    			jLabel5.setText("You Lose");
		    			loss++;
		    		}
		    	}
		    	
		    	jLabel6.setText("Wins: " + win + "   Losses: " + loss);
	    	
	    	}
	    	else{
	    		jTextField1.setText("Try Again");
	    	}
	    }//end jButton1MouseReleased
	    
	    private void jButton2MouseReleased(java.awt.event.MouseEvent evt) {   
	    	win = 0; 
	    	loss = 0;
	    	
	    	jLabel6.setText("Wins: " + win + "   Losses: " + loss);
	    }
	    
	    // Variables declaration                    
	    private javax.swing.JButton jButton1;
	    private javax.swing.JButton jButton2;
	    private javax.swing.JLabel jLabel1;
	    private javax.swing.JLabel jLabel2;
	    private javax.swing.JLabel jLabel3;
	    private javax.swing.JLabel jLabel4;
	    private javax.swing.JLabel jLabel5;
	    private javax.swing.JLabel jLabel6;
	    private javax.swing.JSeparator jSeparator1;
	    private javax.swing.JSeparator jSeparator2;
	    private javax.swing.JSeparator jSeparator3;
	    private javax.swing.JTextField jTextField1;
	    private javax.swing.JTextField jTextField2;
	    private int win, loss;
	}//end pnlRPS

	public class pnlRecognize extends javax.swing.JPanel implements Runnable{

	    /** Creates new form pnlRPS */
	    public pnlRecognize() {
	        initComponents();
	    }

	    @SuppressWarnings("unchecked")
	    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
	    private void initComponents() {
	    	
	        jLabel1 = new javax.swing.JLabel();
	        jLabel2 = new javax.swing.JLabel();
	        
	        setPreferredSize(new Dimension(500, 500));

	        setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

	        jLabel1.setFont(new Font("Serif", Font.BOLD, 36));
	        jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
	        jLabel1.setVerticalAlignment(SwingConstants.CENTER);		        
	        add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 0, 1000, 50));

	        jLabel2.setHorizontalAlignment(SwingConstants.CENTER);
	        jLabel2.setVerticalAlignment(SwingConstants.CENTER);	        
	        jLabel2.setIcon(icon);
	        add(jLabel2, new org.netbeans.lib.awtextra.AbsoluteConstraints(0, 50, 1000, 650));
	        
	    }//end initComponents 
	 
	    @SuppressWarnings("deprecation")
		private void findGestures(boolean start){
	    	if(start){
	    		gestRec = new Thread(this);
	    		gestRec.start();
	    	}
	    	else
	    		gestRec.stop();
	    }
	    
	    public void run(){
	    	//MY TEST CODE	    	
	    	/*int i=0;
	    	int j=0;
	    	
	    	while(true){
	    		icon = new ImageIcon("Images/DSCN1864.JPG");
				jLabel1.setText("Image 1");
				jLabel2.setIcon(icon);
				
				i=0;
				while(i<1000000000){
					i++;
				}
				System.out.println("running");
				i=0;
				icon = new ImageIcon("Images/DSCN1868.JPG");
				jLabel1.setText("Image 2");
				jLabel2.setIcon(icon);
				
				while(i<1000000000){
					i++;
				}
				j++;
	    	}*/
	    	
	    	count = 0;
	    	String gestToHold = "";
	    	String displayText = "";
	    	
	    	while(true){
	    		String gestureName = model.recognize();
	    		//String gestureName = "point2";			//MY TEST CODE
	    		
	    		if(count==0){									//Check if its the first time being detected
	    			gestToHold = gestureName;
	    			count++;
	    		}
	    		else if(count>0){									//Check if its not the first time
	    			if(gestToHold.equalsIgnoreCase(gestureName)){//if its the same as the previous keep going
	    				count++;
	    			}
	    			else{										//else start over
	    				count = 0;
	    			}
	    			
	    			if(count == 10){							//finally if its been 10 times display the text and picture
	    				icon = new ImageIcon("Images/"+gestToHold+".JPG");
	    				displayText = getStringFromCamalCase(gestToHold);
	    				if(displayText.equalsIgnoreCase("point2")) displayText = "Point";	//silly catch for the second kind of point. I was lazy
	    				jLabel1.setText(displayText);
	    				jLabel2.setIcon(icon);    				
	    				count = 0;
	    			}    				
	    		}
	    	}//end while
	    }
	    
	    private javax.swing.JLabel jLabel1;
	    private javax.swing.JLabel jLabel2;
	    private int count;
	    private Icon icon;   
	    private Thread gestRec;
	}//end pnlRecognize
	
	//method to tear apart our camal case gesture names into separate words
	public String getStringFromCamalCase(String s){
		char[] cArray = s.toCharArray();
		String finalStr = "";
		String temp = "";
		   
		temp = temp + Character.toUpperCase(cArray[0]);
		
		for (int i = 1; i < cArray.length; i++) {
			char c = cArray[i];
			if (c >= 65 && c <= 90) {
				finalStr = finalStr + temp + " ";
				temp = "" + c;
			}
			else
				temp = temp + c;
		}
		
		finalStr = finalStr + temp;	
		return finalStr;
	}//end getStringFromCamalCase
	
	JTabbedPane tabbedPane ;	 
	GestureMain model;
	
	public void addComponentToPane(Container pane) {
		
	    tabbedPane = new JTabbedPane();
	
	    pnlBeginCalibration = new Pantomime.pnlBeginCalibration();
	    pnlBeginCalibration.setMinimumSize(pnlBeginCalibration.getPreferredSize());
	    pnlBeginCalibration.setMaximumSize(pnlBeginCalibration.getPreferredSize());
		pnlRPS1 = new pnlRPS();
		pnlRecognize = new pnlRecognize();
		/*pnlRecognize.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent evt){
				JTabbedPane tpane = (JTabbedPane)evt.getSource();
				int sel = tpane.getSelectedIndex();
			}
		});*/
		
		model = new GestureMain();
	    model.init();
	    
		pnlModel = new pnlModel(model);	
	    
	    tabbedPane.addTab("Calibrate", pnlBeginCalibration);
		tabbedPane.addTab("Rock, Paper, Scissors", pnlRPS1);
		tabbedPane.addTab("3D Model", pnlModel);
		tabbedPane.addTab("Gesture Recognition", pnlRecognize);
		
		ChangeListener changeListener = new ChangeListener(){
			public void stateChanged(ChangeEvent evt){
				JTabbedPane tpane = (JTabbedPane)evt.getSource();
				int sel = tpane.getSelectedIndex();
				//System.out.println("Selected Tab: " + sel);		uncomment for debug
				if(sel==3){
					pnlRecognize.findGestures(true);
				}
				else
					pnlRecognize.findGestures(false);
			}
		};
		
		tabbedPane.addChangeListener(changeListener);
		
		pane.add(tabbedPane, BorderLayout.CENTER);        
    }
    
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("Pantomime");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        Pantomime display = new Pantomime();
        display.addComponentToPane(frame.getContentPane());

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Pantomime.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Pantomime.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Pantomime.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Pantomime.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
            	createAndShowGUI();
            }
        });
    }
    
    // Variables declaration                     
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenuBar jMenuBar1;
    private Pantomime.pnlRPS pnlRPS1;
    private Pantomime.pnlBeginCalibration pnlBeginCalibration;
    private Pantomime.pnlRecognize pnlRecognize;
    private GUI.pnlModel pnlModel;                  
}